/**************************************************************************\
    The class "GlassHelper" and the "GlassStateChangeEventArgs" class in this file based on work done for Amuse
    you can find the project's website at http://amuse.codeplex.com
    Amuse has been licensed under the New BSD License


         Copyright (c) 2009, Nidonocu and other Contributors
         All rights reserved.
            
         Redistribution and use in source and binary forms, with or without modification, are permitted 
         provided that the following conditions are met:
            
         * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
            
         * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer 
           in the documentation and/or other materials provided with the distribution.
            
         * Neither the name of the Amuse project nor the names of its contributors may be used to endorse or promote products derived 
           from this software without specific prior written permission.
            
         THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 
         INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
         DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
         SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
         LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
         STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
         ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  
 
 \**************************************************************************/


using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media;

namespace yaTDL
{
    /// <summary>
    /// Provides support for Aero Glass and glow effects on Windows Vista.
    /// The class "GlassHelper" and the "GlassStateChangeEventArgs" class in this file based on work done for Amuse.
    /// You can find the project's website at http://amuse.codeplex.com
    /// Amuse has been licensed under the New BSD License
    /// </summary>
    public static class GlassHelper
    {
        #region Imports and API Support

        /// <summary>
        /// Window Message Value when DWM turns on or off
        /// </summary>
        public const int WM_DWMCOMPOSITIONCHANGED = 0x031E;
        ///// <summary>
        ///// Window Message Value when an application's non-client window area has changed
        ///// </summary>
        //public const int WM_DWMNCRENDERINGCHANGED = 0x031F;
        /// <summary>
        /// Window Message Value when user adjusts colour or transparency options
        /// </summary>
        public const int WM_DWMCOLORIZATIONCOLORCHANGED = 0x0320;
        /// <summary>
        /// Window Message Value when an application has become full screen
        /// </summary>
        /// <remarks>Used by Taskbar and Sidebar to turn dark for example</remarks>
        public const int WM_DWMWINDOWMAXIMIZEDCHANGE = 0x0321;

        [DllImport("dwmapi.dll")]
        private static extern void DwmIsCompositionEnabled(ref bool pfEnabled);
        [DllImport("dwmapi.dll")]
        private static extern void DwmGetColorizationColor(ref int pcrColorization, ref bool pfOpaqueBlend);
        [DllImport("dwmapi.dll")]
        private static extern void DwmExtendFrameIntoClientArea(IntPtr hWnd, ref MARGINS pMargins);
        [DllImport("dwmapi.dll")]
        private static extern void DwmEnableBlurBehindWindow(IntPtr hWnd, ref DWM_BLURBEHIND pBlurBehind);
        //[DllImport("gdi32.dll")]
        //static extern IntPtr CreateRectRgn(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect);


        //[DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
        //private static extern IntPtr CreateCompatibleDC(IntPtr hDC);
        //[DllImport("gdi32.dll", ExactSpelling = true)]
        //private static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject);
        //[DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
        //private static extern bool DeleteObject(IntPtr hObject);
        //[DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
        //private static extern bool DeleteDC(IntPtr hdc);
        //[DllImport("gdi32.dll")]
        //private static extern bool BitBlt(IntPtr hdc, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, uint dwRop);
        //[DllImport("UxTheme.dll", CharSet = CharSet.Unicode)]
        //private static extern int DrawThemeTextEx(IntPtr hTheme, IntPtr hdc, int iPartId, int iStateId, string text, int iCharCount, int dwFlags, ref RECT pRect, ref DTTOPTS pOptions);
        //[DllImport("gdi32.dll")]
        //private static extern IntPtr CreateDIBSection(IntPtr hdc, BITMAPINFO pbmi, uint iUsage, int ppvBits, IntPtr hSection, uint dwOffset);


        [StructLayout(LayoutKind.Sequential)]
        private struct DWM_BLURBEHIND
        {
            public int dwFlags;
            public bool fEnable;
            public IntPtr hRgnBlur;
            public bool fTransitionOnMaximized;
        }

        private const int DWM_BB_ENABLE = 1;
        private const int DWM_BB_BLURREGION = 2;
        private const int DWM_BB_TRANSITIONONMAXIMIZED = 4;

        [StructLayout(LayoutKind.Sequential)]
        private struct DTTOPTS
        {
            public int dwSize;
            public int dwFlags;
            public int crText;
            public int crBorder;
            public int crShadow;
            public int iTextShadowType;
            public POINT ptShadowOffset;
            public int iBorderSize;
            public int iFontPropId;
            public int iColorPropId;
            public int iStateId;
            public bool fApplyOverlay;
            public int iGlowSize;
            public int pfnDrawTextCallback;
            public IntPtr lParam;
        }

        private const int DTT_COMPOSITED = 8192;
        private const int DTT_GLOWSIZE = 2048;
        private const int DTT_TEXTCOLOR = 1;

        [StructLayout(LayoutKind.Sequential)]
        private struct POINT
        {
            //public POINT(int x, int y)
            //{
            //    this.x = x;
            //    this.y = y;
            //}

            public int x;
            public int y;
        }

        //[StructLayout(LayoutKind.Sequential)]
        //private class BITMAPINFO
        //{
        //    public int biSize;
        //    public int biWidth;
        //    public int biHeight;
        //    public short biPlanes;
        //    public short biBitCount;
        //    public int biCompression;
        //    public int biSizeImage;
        //    public int biXPelsPerMeter;
        //    public int biYPelsPerMeter;
        //    public int biClrUsed;
        //    public int biClrImportant;
        //    public byte bmiColors_rgbBlue;
        //    public byte bmiColors_rgbGreen;
        //    public byte bmiColors_rgbRed;
        //    public byte bmiColors_rgbReserved;
        //}

        [StructLayout(LayoutKind.Sequential)]
        private struct MARGINS
        {
            public int left, right, top, bottom;
        }

        //[StructLayout(LayoutKind.Sequential)]
        //private struct RECT
        //{
        //    public int Left;
        //    public int Top;
        //    public int Right;
        //    public int Bottom;

        //    public RECT(int left, int top, int right, int bottom)
        //    {
        //        Left = left;
        //        Top = top;
        //        Right = right;
        //        Bottom = bottom;
        //    }

        //    public RECT(Rectangle rectangle)
        //    {
        //        Left = rectangle.X;
        //        Top = rectangle.Y;
        //        Right = rectangle.Right;
        //        Bottom = rectangle.Bottom;
        //    }

        //    public Rectangle ToRectangle()
        //    {
        //        return new Rectangle(Left, Top, Right - Left, Bottom - Top);
        //    }

        //    public override string ToString()
        //    {
        //        return "Left: " + Left + ", " + "Top: " + Top + ", Right: " + Right + ", Bottom: " + Bottom;
        //    }
        //}
        #endregion

        /// <summary>
        /// Bool value indicating if the OS is Windows Vista (or higher) and that desktop composition is enabled
        /// </summary>
        public static bool IsCompositionEnabled
        {
            get
            {
                if (Environment.OSVersion.Version.Major < 6)
                    return false;

                bool compositionEnabled = false;
                DwmIsCompositionEnabled(ref compositionEnabled);
                return compositionEnabled;
            }
        }

        /// <summary>
        /// Colour value indicating the current colour of the glass
        /// </summary>
        public static System.Windows.Media.Color GlassColour
        {
            get
            {
                if (IsCompositionEnabled)
                {
                    bool opaque = false;
                    int i = 0;
                    DwmGetColorizationColor(ref i, ref opaque);
                    //int i = Convert.ToInt32(u);
                    System.Drawing.Color Dcol = System.Drawing.Color.FromArgb(i);
                    System.Windows.Media.Color WMcol = System.Windows.Media.Color.FromRgb(Dcol.R, Dcol.G, Dcol.B);
                    return WMcol;
                }
                else
                {
                    return System.Windows.SystemColors.GradientActiveCaptionColor;
                }
            }
        }

        /// <summary>
        /// Allows the specified area of a window's client-area to be rendered with glass
        /// </summary>
        /// <remarks>Set any value to '-1' and all others to '0' to render the entire client-area with glass (plate glass mode)</remarks>
        /// <param name="window">The window to be rendered with glass</param>
        /// <param name="margin">The margins to extend glass inward by</param>
        public static void ExtendGlassIntoClientArea(Window window, Thickness margin)
        {
            //Sanity check
            if (!IsCompositionEnabled)
                return;

            System.Drawing.Graphics desktop = System.Drawing.Graphics.FromHwnd(new WindowInteropHelper(window).Handle);
            float DesktopDpiX = desktop.DpiX;
            float DesktopDpiY = desktop.DpiY;

            MARGINS m = new MARGINS();
            m.left = Convert.ToInt32(margin.Left * (DesktopDpiX / 96));
            m.right = Convert.ToInt32(margin.Right * (DesktopDpiX / 96));
            m.top = Convert.ToInt32(margin.Top * (DesktopDpiY / 96));
            m.bottom = Convert.ToInt32(margin.Bottom * (DesktopDpiY / 96));

            HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(window).Handle);

            SolidColorBrush background = new SolidColorBrush(Colors.Red);
            background.Opacity = 0.5;
            window.Background = System.Windows.Media.Brushes.Transparent;
            source.CompositionTarget.BackgroundColor = Colors.Transparent;
            DwmExtendFrameIntoClientArea(source.Handle, ref m);
        }

        /// <summary>
        /// Performs client area glass rendering without hiding client area borders
        /// </summary>
        /// <param name="window">The window to perform the glass rendering on</param>
        /// <param name="enable">If the glass rendering should be enabled or disabled</param>
        /// <param name="maxRender">If the form should be rendered as though windows are maximised</param>
        public static void BlurBehind(Window window, bool enable, bool maxRender)
        {
            DWM_BLURBEHIND bb = new DWM_BLURBEHIND();
            bb.dwFlags = (DWM_BB_ENABLE | DWM_BB_TRANSITIONONMAXIMIZED);
            bb.fEnable = enable;
            bb.fTransitionOnMaximized = maxRender;
            //bb.hRgnBlur = null;// CreateRectRgn(bounds.Left, bounds.Top, bounds.Right, bounds.Bottom);
            HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(window).Handle);
            DwmEnableBlurBehindWindow(source.Handle, ref bb);
        }

        /// <summary>
        /// Renders text with a set standard glow size
        /// </summary>
        public const int StandardGlow = 5;

        ///// <summary>
        ///// Draws text with an external glow to look nice on glass
        ///// </summary>
        ///// <param name="graphics">The graphics object to perform the rendering</param>
        ///// <param name="text">The string to write</param>
        ///// <param name="font">The font size and face</param>
        ///// <param name="bounds">The bounds in which to draw the text</param>
        ///// <param name="color">The forecolour for the text</param>
        ///// <param name="flags">A set of options for rendering the text</param>
        ///// <param name="glowsize">Value indicating the size of the glow around the text</param>
        //public static void DrawGlowingText(Graphics graphics, string text, Font font, Rectangle bounds, Color color, TextFormatFlags flags, int glowsize)
        //{
        //    //Sanity check
        //    if (!IsCompositionEnabled)
        //        return;

        //    IntPtr primaryHdc = graphics.GetHdc();

        //    // Create a memory DC so we can work offscreen
        //    IntPtr memoryHdc = CreateCompatibleDC(primaryHdc);

        //    // Create a device-independent bitmap and select it into our DC
        //    BITMAPINFO info = new BITMAPINFO();
        //    info.biSize = Marshal.SizeOf(info);
        //    info.biWidth = bounds.Width;
        //    info.biHeight = -bounds.Height;
        //    info.biPlanes = 1;
        //    info.biBitCount = 32;
        //    info.biCompression = 0; // BI_RGB
        //    IntPtr dib = CreateDIBSection(primaryHdc, info, 0, 0, IntPtr.Zero, 0);
        //    SelectObject(memoryHdc, dib);

        //    // Create and select font
        //    IntPtr fontHandle = font.ToHfont();
        //    SelectObject(memoryHdc, fontHandle);

        //    // Draw glowing text
        //    System.Windows.Forms.VisualStyles.VisualStyleRenderer renderer = new System.Windows.Forms.VisualStyles.VisualStyleRenderer(System.Windows.Forms.VisualStyles.VisualStyleElement.Window.Caption.Active);
        //    DTTOPTS dttOpts = new DTTOPTS();
        //    dttOpts.dwSize = Marshal.SizeOf(typeof(DTTOPTS));
        //    dttOpts.dwFlags = DTT_COMPOSITED | DTT_GLOWSIZE | DTT_TEXTCOLOR;
        //    dttOpts.crText = ColorTranslator.ToWin32(color);
        //    dttOpts.iGlowSize = glowsize; // This is about the size Microsoft Word 2007 uses
        //    RECT textBounds = new RECT(0, 0, bounds.Right - bounds.Left, bounds.Bottom - bounds.Top);
        //    DrawThemeTextEx(renderer.Handle, memoryHdc, 0, 0, text, -1, (int)flags, ref textBounds, ref dttOpts);

        //    // Copy to foreground
        //    const int SRCCOPY = 0x00CC0020;
        //    BitBlt(primaryHdc, bounds.Left, bounds.Top, bounds.Width, bounds.Height, memoryHdc, 0, 0, SRCCOPY);

        //    // Clean up
        //    DeleteObject(fontHandle);
        //    DeleteObject(dib);
        //    DeleteDC(memoryHdc);

        //    graphics.ReleaseHdc(primaryHdc);
        //}

    }

    /// <summary>
    /// Event arguments which read the GlassState information automatically for use by other classes
    /// </summary>
    public class GlassStateChangeEventArgs : EventArgs
    {
        bool newState;

        /// <summary>
        /// The glass state as of right now
        /// </summary>
        public bool GlassState
        {
            get { return newState; }
        }

        /// <summary>
        /// Constructs a GlassStateChangeEventArgs and reads the current Glass state
        /// </summary>
        public GlassStateChangeEventArgs()
        {
            newState = GlassHelper.IsCompositionEnabled;
        }
    }
}


             

       



